macOS Safari 脚本加载
Safari 浏览器脚本通过 Safari Web Extension 在 Safari 页面中运行用户脚本。运行时支持类似 Greasemonkey / 油猴的 GM.* API,并提供部分 Scripting API。
脚本运行位置
目前有两类脚本来源:
- Scripting 脚本项目中的
browser.tsx,构建后会生成browser.js。 - 从 Safari 扩展弹窗安装的
.user.js/.js脚本。
从 Safari 扩展弹窗安装的脚本会保存到:
下载文件和 GM 存储也在同一个根目录下:
这个根目录会跟随 Settings 中配置的 Safari Browser Data 存储位置,包括启用 WebDAV 时的同步位置。
脚本格式
创建或安装 .user.js / .js 文件,并包含 userscript 头:
常用元数据:
@weight 用于控制多个匹配脚本的执行顺序,数值越大越先执行。如果没有写 @run-at,默认在 document-end 运行。
@inject-into 默认为 auto。在 auto 下,声明了任意 @grant(GM.* 或 Scripting.*)的脚本运行在 content world(可用特权 API,与页面 JavaScript 隔离);而 @grant none 或未声明 grant 的脚本运行在 page world(共享页面真实 window,可读页面全局变量)。可用 @inject-into content 或 @inject-into page 显式指定世界。GM.*、Scripting.* 和扩展消息能力只在 content world 可用;page world 下 grant 会被忽略。在 Content-Security-Policy 拦截注入脚本的页面上,auto 的 page-world 脚本会自动回退到 content world。
权限
特权 API 需要通过 @grant 声明:
@grant none 会关闭 GM API,但为了兼容已有用户脚本,GM_info 和 GM.info 仍然可以访问。
跨域网络、下载、资源和 Cookie 访问需要通过 @connect 允许:
缺少权限时,运行时会抛出带稳定 code 的错误,例如 permissionDenied 或 connectDenied。
GM_info
GM_info 和 GM.info 会暴露解析后的元数据和运行时信息:
已支持的 GM API
存储
GM 存储会以 JSON 文件保存到 scripting-safari-extension/storages/。
DOM 和菜单
菜单命令会显示在当前页面的 Safari 扩展弹窗中。
标签页、剪贴板、通知
GM.closeTab() 会在 Safari 支持时关闭当前标签页。GM.openInTab() 会返回带 close() 方法的标签页控制对象。
资源
资源需要在 userscript 头中声明:
下载
下载文件会保存到 scripting-safari-extension/downloads/。
XHR
运行时支持 text、json、arraybuffer、blob 和 document 类型,也支持 user、password、headers、data、timeout、binary、overrideMimeType、upload 回调、finalUrl 和 responseURL。
Cookie
默认情况下,GM.cookie.list、set 和 delete 使用运行脚本的标签页对应的 Cookie store,包括该标签页的 Safari 个人资料或无痕会话。显式 storeId 可覆盖此选择。Safari 无法唯一确定来源标签页的 store 时会报错,不会改用扩展后台的默认 store。浏览器网站授权与 @connect 规则仍然适用。Cookie 可见性也受 domain、path、Secure 和 HttpOnly 属性影响;document.cookie 无法读取 HttpOnly Cookie。
也支持 callback 风格:
Scripting.FileManager
使用 @grant Scripting.FileManager 或 @grant Scripting.* 开启 API。
属性
在普通 Scripting app 脚本中,也可以通过 FileManager.safariBrowserDirectory、FileManager.safariBrowserStorageDirectory、FileManager.safariBrowserDownloadsDirectory 和 FileManager.safariBrowserUserscriptsDirectory 访问同一套 Safari 数据目录。
方法
所有文件操作都被限制在 Scripting.FileManager 暴露的目录下。
Scripting.tabs
使用 @grant Scripting.tabs(或 @grant Scripting.*)枚举并切换 Safari 中真实打开的标签页。
它与 GM.getTabs 不同:GM.getTabs 是每个脚本的存储总线,只返回你自己用 GM.saveTab 存过的数据,不列出真实标签页或其 URL。Scripting.tabs 返回的是真正打开的标签页。
方法
每个标签页是一个 ScriptingTabInfo:
新开标签用 GM.openInTab(url);关闭标签用 GM.closeTab(id)(id 取自 query())。Scripting.tabs.activate() 只切换焦点,不会新开标签。单个 Safari 窗口内 activate() 会选中该标签;跨多个窗口时只在其所属窗口内选中。
隐私: 授予
Scripting.tabs的脚本能读取所有打开标签页的 URL 与标题,而不仅是它运行的页面。只把该权限授予你信任的脚本。Userscript 需在该页面允许 Scripting 扩展,且必须显式声明此 grant。
已安装脚本
Safari 扩展弹窗支持从当前页面或 URL 安装 userscript。已安装脚本可以在弹窗和 More > Development > Safari Browser Scripts 中启用、禁用、更新或删除。
More 页面可以查看:
- 已安装的 userscript。
- GM 存储 JSON 文件。
GM.download下载的文件。
示例
无 UI 翻译(iOS/macOS 26+)
声明 // @grant Scripting.Translation 后,在 content world 使用 Scripting.Translation.translateInstalled({text, source, target?}) 或 translateInstalledBatch({texts, source, target?})。需要已经安装的语言,源语言必填。Safari 只提供这两个新的无 UI 方法,不提供下载语言包或翻译宿主。单次最多 64 条文本、256 KiB UTF-8 文本。详见Translation 文档。
自动安装页识别
脚本加载支持存储目录的路径别名。解析符号链接后,文件仍须位于允许的脚本存储目录中;指向目录外文件的链接会被拒绝。permissionDenied 表示路径校验未通过,assetFetchFailed 表示允许访问的脚本文件无法读取。
.js 链接可指向允许目录内使用其他后缀的普通文件。加载时固定已打开的文件,拒绝校验后替换的符号链接及命名管道等非普通文件。
只有当前主页面是原始脚本文本,且文件开头有完整、顺序正确、包含非空 @name(可本地化)的 userscript 注释头时,才会自动打开安装页。允许头部前的 BOM、空白和许可注释;配置中的嵌入代码、字符串示例和 HTML 代码示例不会触发。.conf、.ini、.yaml、.yml、.json、.toml 和 .mobileconfig 地址不自动跳转。
跳转前会确认仍在同一来源文档,离开页面或重载后,旧检测请求会取消。可关闭自动安装跳转;从安装页返回源码不会立即再次跳转。通过 URL 手动安装仍支持原始脚本端点,但安装内容同样必须有有效的开头元数据块。
从安装页返回来源,或点击安装页的来源链接,会在同一标签页查看脚本源码;扩展后台重新加载后也保留返回保护。标签页离开来源及其安装页或关闭后,保护结束。“完成/关闭”会关闭该标签页。
